package com.sunyard.utils.manage;

import com.amazonaws.AmazonServiceException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.sunyard.constant.manage.ManageConstant;
import com.sunyard.constant.msg.ConfCache;
import com.sunyard.myEnum.UrlEnum;
import com.sunyard.utils.ftputil.SFTPUtils;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author:zih.sun
 * @description 对象存储工具类
 */
@Slf4j
public class EosFileUtils {

    static AmazonS3 client;

    static {
        //初始化S3 configure 的实例
        ClientConfiguration config = new ClientConfiguration();
        config.setConnectionTimeout(10000);
        config.setSocketTimeout(300000);
        config.setProtocol(Protocol.HTTP);
        config.setUseExpectContinue(false);

        AWSCredentials credentials = new BasicAWSCredentials(ConfCache.getValue("amazon.accessKeyId"),
                ConfCache.getValue("amazon.secretKey"));

        AwsClientBuilder.EndpointConfiguration end_point = new AwsClientBuilder.EndpointConfiguration(
                ConfCache.getValue("amazon.endPoint"), "");

        //创建连接客户端
        client = AmazonS3ClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withClientConfiguration(config)
                .withEndpointConfiguration(end_point)
                .withPathStyleAccessEnabled(true)
                .build();
    }

    /**
     * 上传文件
     *
     * @param key  唯一标识 src/main/resources/文件名
     * @param file 文件
     * @return 文件访问路径
     * @author:zih.sun
     */
    public static String uploadDtcFile(String key, File file) throws Exception {
        // 设置对象元数据
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(key.substring(key.lastIndexOf("."))));
        metadata.setContentEncoding("utf-8");
        metadata.setCacheControl("no-cache");
        metadata.setHeader("Pragma", "no-cache");
        metadata.setCacheControl("public,max-age=31536000");
        PutObjectRequest putRequest = new PutObjectRequest(ConfCache.getValue("amazon.bucketName"), key, file)
                .withCannedAcl(CannedAccessControlList.PublicRead);
        putRequest.setMetadata(metadata);
        String url = null;
        try {
            // 上传文件
            client.putObject(putRequest);
            //返回路径
            String value = ConfCache.getValue("amazon.endpoint.bucket");
            url = value + key;
        } catch (AmazonServiceException ase) {
            log.error("上传文件key：{}，失败：{}", key, ase);
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (Exception e) {
            log.error("上传文件key：{}，失败：{}", key, e);
            throw e;
        }
        return url;
    }

    /**
     * 上传文件
     *
     * @param key  唯一标识 src/main/resources/文件名
     * @param file 文件
     * @return 文件访问路径
     * @author:zih.sun
     */
    public static String uploadFileInner(String key, File file) throws Exception {
        // 设置对象元数据
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(key.substring(key.lastIndexOf("."))));
        metadata.setContentEncoding("utf-8");
        metadata.setCacheControl("no-cache");
        metadata.setHeader("Pragma", "no-cache");
        metadata.setCacheControl("public,max-age=31536000");
        PutObjectRequest putRequest = new PutObjectRequest(ConfCache.getValue("amazon.bucketName"), key, file)
                .withCannedAcl(CannedAccessControlList.PublicRead);
        putRequest.setMetadata(metadata);
        String url = null;
        try {
            // 上传文件
            client.putObject(putRequest);
            //返回路径
            String value = ConfCache.getValue("amazon.endpoint.bucket");
            url = UrlEnum.getValue(value) + key;
        } catch (AmazonServiceException ase) {
            log.error("上传文件key：{}，失败：{}", key, ase);
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (Exception e) {
            log.error("上传文件key：{}，失败：{}", key, e);
            throw e;
        }
        return url;
    }


    /**
     * 上传文件
     *
     * @param key  唯一标识 src/main/resources/文件名
     * @param file 文件
     * @return 文件访问路径
     * @author:zih.sun
     */
    public static String uploadFile(String key, File file) throws Exception {
        // 设置对象元数据
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(getContentType(key.substring(key.lastIndexOf("."))));
        metadata.setContentEncoding("utf-8");
        metadata.setCacheControl("no-cache");
        metadata.setHeader("Pragma", "no-cache");
        metadata.setCacheControl("public,max-age=31536000");
        PutObjectRequest putRequest = new PutObjectRequest(ConfCache.getValue("amazon.bucketName"), key, file)
                .withCannedAcl(CannedAccessControlList.PublicRead);
        putRequest.setMetadata(metadata);
        String url = null;
        try {
            // 上传文件
            client.putObject(putRequest);
            //返回路径
            String value = ConfCache.getValue("amazon.endpoint.bucket");
            url = UrlEnum.getValue(value) + key;
        } catch (AmazonServiceException ase) {
            log.error("上传文件key：{}，失败：{}", key, ase);
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (Exception e) {
            log.error("上传文件key：{}，失败：{}", key, e);
            throw e;
        }
        return url;
    }


    /**
     * 下载文件 返回文件流
     *
     * @param key 唯一标识
     * @return
     * @author:zih.sun
     */
    public static void downloadFile(String key, HttpServletResponse response) throws Exception {
        try {
            // 获取文件对象
            S3Object object = client.getObject(new GetObjectRequest(ConfCache.getValue("amazon.bucketName"), key));
            ObjectMetadata objectMetadata = object.getObjectMetadata();
            response.setContentType(objectMetadata.getContentType());
            // 流输出文件
            ServletOutputStream outputStream = response.getOutputStream();
            InputStream inputStream = object.getObjectContent();
            byte b[] = new byte[2048];
            int n;
            //循环读取 !=-1读取完毕
            while ((n = inputStream.read(b)) != -1) {
                //写入到输出流 从0读取到n
                outputStream.write(b, 0, n);
            }
            //关闭流、释放资源
            outputStream.close();
            inputStream.close();
            // 关闭文件流
            object.close();
        } catch (AmazonServiceException ase) {
            log.error("下载文件key：{},失败：{}", key, ase);
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (Exception e) {
            log.error("下载文件key：{},失败：{}", key, e);
            throw e;
        }
    }

    /**
     * 单个删除对象
     *
     * @param key 文件对象唯一标识
     * @author:zih.sun
     */
    public static void deleteFile(String key) throws Exception {
        try {
            client.deleteObject(ConfCache.getValue("amazon.bucketName"), key);
        } catch (AmazonServiceException ase) {
            log.error("删除文件key:{},失败：{}", key, ase);
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (Exception e) {
            log.error("删除文件key:{},失败：{}", key, e);
            throw e;
        }
    }

    /**
     * 获取文件对象的byte数组
     *
     * @param key 文件唯一标识
     * @return
     * @author:zih.sun
     */
    public static byte[] downloadFileByte(String key) throws Exception {
        try {
            S3Object object = client.getObject(new GetObjectRequest(ConfCache.getValue("amazon.bucketName"), key));
            return SFTPUtils.toByteArray(object.getObjectContent());
        } catch (AmazonServiceException ase) {
            log.error("下载文件key：{}，失败：{}", key, ase);
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (IOException e) {
            log.error("下载文件失败：{}", e);
            throw e;
        }
    }


    /**
     * 获取对象元数据
     *
     * @param key
     * @return
     */
    public static ObjectMetadata getMetaData(String key) {
        try {
            return client.getObjectMetadata(ConfCache.getValue("amazon.bucketName"), key);
        } catch (AmazonServiceException ase) {
            log.error("获取对象元数据key：{}，失败：{}", key, ase);
            log.error("Error Message:    " + ase.getMessage() + "\n");
            log.error("HTTP Status Code: " + ase.getStatusCode() + "\n");
            log.error("AWS Error Code:   " + ase.getErrorCode() + "\n");
            log.error("Error Type:       " + ase.getErrorType() + "\n");
            log.error("Request ID:       " + ase.getRequestId() + "\n");
            throw ase;
        } catch (Exception e) {
            log.error("获取对象元数据key：{}，失败：{}", key, e);
            throw e;
        }
    }

    /**
     * 使用分页操作列出大量对象
     */
    public static void listObjects() {
        ListObjectsV2Request req = new ListObjectsV2Request().withBucketName(ConfCache.getValue("amazon.bucketName"));
        ListObjectsV2Result result;
        try {
            do {
                result = client.listObjectsV2(req);
                for (S3ObjectSummary objectSummary : result.getObjectSummaries()) {
                    System.out.printf(" - %s (size: %d)\n", objectSummary.getKey(), objectSummary.getSize());
                }
                //获取继续获取对象列表的Token
                String token = result.getNextContinuationToken();
                log.error("Next Continuation Token: " + token);
                req.setContinuationToken(token);
            } while (result.isTruncated());
        } catch (AmazonServiceException e) {
            e.printStackTrace();
        }
    }


    /**
     * 批量删除
     *
     * @param listKeys
     */
    public static void deleteObjectS(List<DeleteObjectsRequest.KeyVersion> listKeys) {
        DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(ConfCache.getValue("amazon.bucketName"));
        deleteRequest.withKeys(listKeys);
        try {
            client.deleteObjects(deleteRequest);
        } catch (AmazonServiceException ase) {
            log.error("Caught an AmazonServiceException when delete objects as below:");
            for (DeleteObjectsRequest.KeyVersion key : listKeys) {
                log.error("  key: " + key.getKey() + "; Version: " + key.getVersion());
            }
            log.error("Error Message:    " + ase.getMessage());
            log.error("HTTP Status Code: " + ase.getStatusCode());
            log.error("AWS Error Code:   " + ase.getErrorCode());
            log.error("Error Type:       " + ase.getErrorType());
            log.error("Request ID:       " + ase.getRequestId());
            //System.exit(1);
        }
    }

    /**
     * 复制对象
     *
     * @param sourceKey
     * @param destinationBucketName
     * @param destinationKey
     */
    public static void copyObeject(String sourceKey,
                                   String destinationBucketName,
                                   String destinationKey) {
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.addUserMetadata("Source", "copy");
        CopyObjectRequest copyReq = new CopyObjectRequest(ConfCache.getValue("amazon.bucketName"), sourceKey, destinationBucketName, destinationKey)
                .withNewObjectMetadata(metadata);
        try {
            client.copyObject(copyReq);
            log.error("Success to copy the object: " + sourceKey);
        } catch (AmazonServiceException ase) {
            log.error("Caught an AmazonServiceException when copy object of \"" + ConfCache.getValue("amazon.bucketName") + "\".");
            log.error("Error Message:    " + ase.getMessage());
            log.error("HTTP Status Code: " + ase.getStatusCode());
            log.error("AWS Error Code:   " + ase.getErrorCode());
            log.error("Error Type:       " + ase.getErrorType());
            log.error("Request ID:       " + ase.getRequestId());
            //System.exit(1);
        }
    }


    /**
     * 根据文件类型返回对应contentType
     *
     * @param FilenameExtension
     * @return
     * @author:zih.sun
     */
    public static String getContentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpeg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "application/octet-stream";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "application/octet-stream";
    }

}
